//
//  Container.Arguments.swift
//  Swinject
//
//  Created by Yoichi Tagaya on 8/18/15.
//  Copyright © 2015 Swinject Contributors. All rights reserved.
//

//
// NOTICE:
//
// Container.Arguments.swift is generated from Container.Arguments.erb by ERB.
// Do NOT modify Container.Arguments.swift directly.
// Instead, modify Container.Arguments.erb and run `script/gencode` at the project root directory to generate the code.
//

<% arg_count = 9 %>

import Foundation

// MARK: - Registeration with Arguments
extension Container {
<% (1..arg_count).each do |i| %>
<%   arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<%   arg_description = i == 1 ? "#{i} argument" : "#{i} arguments" %>
    /// Adds a registration for the specified service with the factory closure to specify how the service is resolved with dependencies.
    ///
    /// - Parameters:
    ///   - serviceType: The service type to register.
    ///   - name:        A registration name, which is used to differentiate from other registrations
    ///                  that have the same service and factory types.
    ///   - factory:     The closure to specify how the service type is resolved with the dependencies of the type.
    ///                  It is invoked when the `Container` needs to instantiate the instance.
    ///                  It takes a `Resolver` instance and <%= arg_description %> to inject dependencies to the instance,
    ///                  and returns the instance of the component type for the service.
    ///
    /// - Returns: A registered `ServiceEntry` to configure more settings with method chaining.
    @discardableResult
    public func register<Service, <%= arg_types %>>(
        _ serviceType: Service.Type,
        name: String? = nil,
        factory: @escaping (Resolver, <%= arg_types %>) -> Service) -> ServiceEntry<Service>
    {
        return _register(serviceType, factory: factory, name: name)
    }

<% end %>
}

// MARK: - Resolver with Arguments
extension Container {
<% (1..arg_count).each do |i| %>
<%   arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<%   arg_param_def = i == 1 ? "argument: Arg1" : "arguments arg1: Arg1, " + (2..i).map{ |n| "_ arg#{n}: Arg#{n}" }.join(", ") %>
<%   arg_param_call = i == 1 ? "argument" : (1..i).map{ |n| "arg#{n}" }.join(", ") %>
<%   arg_param_name = i == 1 ? "argument" : "arguments" %>
<%   arg_param_type = i == 1 ? arg_types : "(" + arg_types + ")" %>
<%   arg_param_description = i == 1 ? "#{i} argument" : "list of #{i} arguments" %>
    /// Retrieves the instance with the specified service type and <%= arg_param_description %> to the factory closure.
    ///
    /// - Parameters:
    ///   - serviceType: The service type to resolve.
    ///   - <%= arg_param_name %>:   <%= arg_param_description.capitalize %> to pass to the factory closure.
    ///
    /// - Returns: The resolved service type instance, or nil if no registration for the service type
    ///            and <%= arg_param_description %> is found in the `Container`.
    public func resolve<Service, <%= arg_types %>>(
        _ serviceType: Service.Type,
        <%= arg_param_def %>) -> Service?
    {
        return resolve(serviceType, name: nil, <%= arg_param_name %>: <%= arg_param_call %>)
    }

    /// Retrieves the instance with the specified service type, <%= arg_param_description %> to the factory closure and registration name.
    ///
    /// - Parameters:
    ///   - serviceType: The service type to resolve.
    ///   - name:        The registration name.
    ///   - <%= arg_param_name %>:   <%= arg_param_description.capitalize %> to pass to the factory closure.
    ///
    /// - Returns: The resolved service type instance, or nil if no registration for the service type,
    ///            <%= arg_param_description %> and name is found in the `Container`.
    public func resolve<Service, <%= arg_types %>>(
        _ serviceType: Service.Type,
        name: String?,
        <%= arg_param_def %>) -> Service?
    {
        typealias FactoryType = ((Resolver, <%= arg_types %>)) -> Any
        return _resolve(name: name) { (factory: FactoryType) in factory((self, <%= arg_param_call %>)) }
    }

<% end %>
}
